/*
 * Low level disk I/O module for bitmap
 */
#include "lib_fs_disk_io_for_bitmap.h"
#include <stdio.h>

#include "lib_fs_disk_io_for_bitmap.private"

#define lib_fs_disk_io_filename    "disk_bitmap.bin"
private FILE      * p_my_disk;
private boolean_t disk_bitmap_block_is_empty[DISK_BLOCK_N];

uint32_t disk_bitmap_get_free_block()
{
    uint32_t  ans;
    uint32_t  i;
    boolean_t is_found;

    ans      = 0;
    i        = 1; /* never use 0, it is reserved */
    is_found = False;
    while ((is_found == False)logicalAnd(i < DISK_BLOCK_N))
    {
        ans = 0;
        if (disk_bitmap_block_is_empty[i] == True)
        {
            is_found = True;
            ans      = i;
        }
        i++;
    }

    if ((i >= DISK_BLOCK_N)logicalAnd(is_found == False))
    {
        deadbeaf("disk_bitmap_get_free_block, disk full");
    }
    return ans;
}

void disk_bitmap_set_used_block(uint32_t i)
{
    boolean_t ans;

    printf("block%ld is used\n", i);
    disk_bitmap_block_is_empty[i] = False;
    /*
     * writeback
     */
    ans = disk_bitmap_block_is_empty[i];
    //ans=~ans;
    disk_bitmap_set(i, ans);
}

void disk_bitmap_set_free_block(uint32_t i)
{
    boolean_t ans;

    printf("block%ld is free\n", i);
    disk_bitmap_block_is_empty[i] = True;
    /*
     * writeback
     */
    ans = disk_bitmap_block_is_empty[i];
    //ans=~ans;
    disk_bitmap_set(i, ans);
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

boolean_t disk_bitmap_load()
{
    boolean_t ans;
    uint32_t  i;

    ans = False;
    if (p_my_disk != NULL)
    {
        for (i = 0; i < DISK_BLOCK_N; i++)
        {
            disk_bitmap_block_is_empty[i] = disk_bitmap_get(i);
        }
        ans = True;
    }
    return ans;
}

boolean_t disk_bitmap_set_free_all_blocks()
{
    boolean_t ans;
    uint32_t  i;

    ans = False;
    if (p_my_disk != NULL)
    {
        for (i = 0; i < DISK_BLOCK_N; i++)
        {
            disk_bitmap_set_free_block(i);
        }
        ans = True;
    }
    return ans;
}

boolean_t disk_bitmap_init
(
    uint8_t diskID                  /* Physical drive nmuber (0..) */
)
{
    boolean_t ans;
    uint32_t  i;

    /*
     * pre init
     */
    for (i = 0; i < DISK_BLOCK_N; i++)
    {
        disk_bitmap_block_is_empty[i] = True;
    }

    /*
     * loading
     */
    p_my_disk = fopen(lib_fs_disk_io_filename, "r+");
    if (p_my_disk != NULL)
    {
        ans = disk_bitmap_load();
    }
    else
    {
        printf("disk_bitmap_init failure\n");
        ans = False;
    }

    return ans;
}

boolean_t disk_bitmap_done
(
    uint8_t diskID
)
{
    boolean_t ans;
    uint32_t  i;
    uint8_t   is_empty;

    if (p_my_disk != NULL)
    {
        fclose(p_my_disk);
        ans = True;
        printf("disk_bitmap_done\n");
        for (i = 0; i < DISK_BLOCK_N; i++)
        {
            is_empty = disk_bitmap_block_is_empty[i];
            if (is_empty == False)
                printf("iblock=%ld, in use\n", i);
        }
    }
    else
    {
        ans = False;
    }

    return ans;
}

private boolean_t disk_bitmap_get
(
    uint32_t iblock
)
{
    boolean_t ans;
    uint32_t  addr;
    uint8_t   disk_value;

    ans = False;
    if (p_my_disk != NULL)
    {
        addr = iblock * sizeof(disk_value);
        fseek(p_my_disk, addr, SEEK_SET);
        fread(&ans, sizeof(disk_value), 1, p_my_disk);
        //ans=~ans;
        //printf("bitmap reading iblock=%lx, value=%d\n", addr, ans);
        //printf("bitmap reading iblock=%lx, value=%d\n", addr, ans);
    }
    else
    {
        deadbeaf("disk_bitmap_get, NULL file");
    }
    return ans;
}

private void disk_bitmap_set
(
    uint32_t iblock,
    boolean_t value
)
{
    uint32_t addr;
    uint8_t  disk_value;

    if (p_my_disk != NULL)
    {
        addr = iblock * sizeof(disk_value);
        fseek(p_my_disk, addr, SEEK_SET);
        disk_value = (uint8_t) value;
        fwrite(&disk_value, sizeof(disk_value), 1, p_my_disk);
        //printf("bitmap writing iblock=%lx, value=%d\n", addr, disk_value);
    }
    else
    {
        deadbeaf("disk_bitmap_set, NULL file");
    }
}

